/**
 * @file FastCluster.h
 * @author shikang999@126.com
 * @brief 主要进行快速聚类
 * @version 0.1
 * @date 2025-11-05
 * 
 * @copyright Copyright (c) 2025
 * 
 */

#pragma once
#include <set>
#include <map>
#include <vector>
#include <memory>
#include <cstdint>

namespace cluster
{

//1. 网格索引类型. 如果使用二维匹配,划分网格过细,则替换成int64_t
using GridInt_t = int32_t;

//2.聚类对象
struct ClusterRes_t;
struct ClusterObject_t
{
    ClusterObject_t(void *srcObj = nullptr): obj(srcObj), id(0), x(0), y(0)
    {

    }

    void *obj;   //关联对象
    uint32_t id; //目标索引,一般调试使用
    double x;    //目标二维位置x,此参数在使用二维距离匹配时设置
    double y;    //目标二维位置y,此参数在使用二维距离匹配时设置
    std::weak_ptr<ClusterRes_t> cluster;
};
using vecClusterObject_t = std::vector<std::shared_ptr<ClusterObject_t>>;
using mapGridObject_t    = std::map<std::pair<GridInt_t, GridInt_t>, vecClusterObject_t>;

//3.聚类结果
struct ClusterRes_t
{
    ClusterRes_t(uint32_t index = 0):id(index)
    {

    }

    uint32_t id;
    vecClusterObject_t vecObject;
};
using setClusterRes_t = std::set<std::shared_ptr<ClusterRes_t>>;
using vecClusterRes_t = std::vector<std::shared_ptr<ClusterRes_t>>;

//4.聚类基类
class FastCluster
{
public:
    FastCluster();
    virtual ~FastCluster();

    //执行聚类函数
    vecClusterRes_t cluster(const vecClusterObject_t &vecObject);

    //如果对象pos有幅值,且有距离限制,则执行本函数, maxDist为最大距离
    vecClusterRes_t clusterFor2D(const vecClusterObject_t &vecObject, const double maxDist);

private:
    //需要重载两个对象是否匹配
    virtual bool isMatch(const std::shared_ptr<ClusterObject_t> &a, const std::shared_ptr<ClusterObject_t> &b) const;

private:
    //遍历聚类
    void clusterCall(const vecClusterObject_t &vecObject, vecClusterRes_t &vecRes) const;

    //单个网格内数据聚类
    void clusterInSingleGrid(const mapGridObject_t &mapObject, vecClusterRes_t &vecCluster) const;

    //领域多网格聚类
    void clusterInMulGrid(const mapGridObject_t &mapObject) const;

    //对象是否和聚类簇匹配
    bool isMatchForCluster(const std::shared_ptr<ClusterObject_t> &obj, const std::shared_ptr<ClusterRes_t> &cluster) const;

    //距离是否满足聚类条件
    inline bool distIsOK(const std::shared_ptr<ClusterObject_t> &a, const std::shared_ptr<ClusterObject_t> &b) const;

    //合并聚类簇
    inline void mergeCluster(std::shared_ptr<ClusterRes_t> &src, std::shared_ptr<ClusterRes_t> &dst) const;

    //计算二维网格索引
    inline std::pair<GridInt_t, GridInt_t> calcGridIndex(const std::shared_ptr<ClusterObject_t> &obj, double dist) const;

    //获取匹配key
    inline std::pair<ClusterObject_t*, ClusterObject_t*> getKey(const std::shared_ptr<ClusterObject_t> &a, const std::shared_ptr<ClusterObject_t> &b) const;

private:
    bool isGrid_ ;       //是否使用网格匹配
    double squaredDist_; //网格匹配时最大平方距离
};

}